﻿using Microsoft.AspNet.SignalR;
using System;
using System.Collections.Generic;
using ZSoft.PushServices.Net.DTO;
using ZSoft.PushServices.Net.Transport.ConnectionEvents;
using Microsoft.AspNet.SignalR.Hubs;

namespace ZSoft.PushServices.Net.Services.NotificationQueue
{
    public class DefaultQueueProvider : INotificationQueueProvider
    {
        private static Lazy<Dictionary<string, Queue<NotificationDTO>>> _factory =
            new Lazy<Dictionary<string, Queue<NotificationDTO>>>(() => new Dictionary<string, Queue<NotificationDTO>>(), true);

        private INotificationService _notifier;
        
        public static DefaultQueueProvider Current
        {
            get
            {
                return (DefaultQueueProvider)GlobalHost.DependencyResolver.GetService(typeof(INotificationQueueProvider));
            }
        }

        private static Dictionary<string, Queue<NotificationDTO>> Store
        {
            get
            {
                return _factory.Value;
            }
        }

        
        public DefaultQueueProvider()
        {
            _notifier = GlobalHost.DependencyResolver.GetService(typeof(INotificationService)) as INotificationService;
            ConnectionEventManager.RegisterHandler(new DefaultQueueProvider.DeviceIdentifiedHandler());
        }

        public Queue<NotificationDTO> Dequeu(string deviceId)
        {
            Queue<NotificationDTO> result = Store[deviceId];
            Store.Remove(deviceId);
            return result;
        }

        public void Enqueue(string deviceId, NotificationDTO item)
        {
            Store[deviceId] = Store[deviceId] ?? new Queue<NotificationDTO>();
            Store[deviceId].Enqueue(item);
        }

        public bool HasPendingNotification(string deviceId)
        {
            return Store.ContainsKey(deviceId);
        }


        public class DeviceIdentifiedHandler : IConnectionEventHandler
        {
            public ConnectionEventTypes Type
            {
                get
                {
                    return ConnectionEventTypes.DeviceIdentified;
                }
            }

            public void Execute(HubCallerContext context, ClientInfoDTO info)
            {
                string deviceId = info.DeviceId;
                if (Current.HasPendingNotification(deviceId))
                {
                    Queue<NotificationDTO> queue = Current.Dequeu(deviceId);
                    while (queue.Count > 0)
                    {
                        Current._notifier.NotifyDevice(deviceId, queue.Dequeue());
                    }
                }
            }
        }

    }
}
